package com.example.aspect;

import com.example.common.OperationLog;
import com.example.entity.User;
import com.example.service.OperationLogService;
import com.example.util.IpUtil;
import com.example.util.UserContextUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 操作日志AOP切面
 */
@Aspect
@Component
public class OperationLogAspect {
    
    @Autowired
    private OperationLogService operationLogService;
    
    @Autowired
    private UserContextUtil userContextUtil;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 定义切点：所有带有@OperationLog注解的方法
     */
    @Pointcut("@annotation(com.example.common.OperationLog)")
    public void operationLogPointcut() {}
    
    /**
     * 环绕通知：记录操作日志
     */
    @Around("operationLogPointcut() && @annotation(operationLog)")
    public Object around(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 获取请求信息
        HttpServletRequest request = getHttpServletRequest();
        
        // 创建日志对象
        com.example.entity.OperationLog log = new com.example.entity.OperationLog();
        
        // 设置基本信息
        setBasicInfo(log, operationLog, request, joinPoint);
        
        Object result = null;
        try {
            // 执行目标方法
            result = joinPoint.proceed();
            
            // 设置成功信息
            log.setStatus("SUCCESS");
            log.setLogLevel("INFO");
            
            // 记录响应结果
            if (operationLog.recordResult() && result != null) {
                try {
                    String resultJson = objectMapper.writeValueAsString(result);
                    // 限制响应结果长度，避免过长
                    if (resultJson.length() > 2000) {
                        resultJson = resultJson.substring(0, 2000) + "...";
                    }
                    log.setResponseResult(resultJson);
                } catch (Exception e) {
                    log.setResponseResult("响应结果序列化失败");
                }
            }
            
        } catch (Exception e) {
            // 设置失败信息
            log.setStatus("FAILURE");
            log.setLogLevel("ERROR");
            log.setErrorMsg(e.getMessage());
            
            // 重新抛出异常
            throw e;
        } finally {
            // 计算执行时间
            long endTime = System.currentTimeMillis();
            log.setExecutionTime(endTime - startTime);
            
            // 异步记录日志
            recordLogAsync(log);
        }
        
        return result;
    }
    
    /**
     * 设置基本信息
     */
    private void setBasicInfo(com.example.entity.OperationLog log, OperationLog annotation, 
                             HttpServletRequest request, JoinPoint joinPoint) {
        
        // 设置用户信息
        try {
            User currentUser = userContextUtil.getCurrentUser();
            if (currentUser != null) {
                log.setUserId(currentUser.getId());
                log.setUsername(currentUser.getUsername());
                log.setNickname(currentUser.getNickname());
            }
        } catch (Exception e) {
            // 获取用户信息失败，可能是匿名访问
            log.setUsername("anonymous");
        }
        
        // 设置注解信息
        log.setModule(annotation.module());
        log.setOperationType(annotation.operationType());
        log.setOperationDesc(annotation.description());
        log.setBusinessType(annotation.businessType());
        log.setLogLevel(annotation.logLevel());
        
        // 设置请求信息
        if (request != null) {
            log.setRequestMethod(request.getMethod());
            log.setRequestUrl(request.getRequestURI());
            log.setIpAddress(IpUtil.getClientIpAddress(request));
            log.setUserAgent(request.getHeader("User-Agent"));
            log.setLocation(IpUtil.getLocationByIp(log.getIpAddress()));
            
            // 记录请求参数
            if (annotation.recordParams()) {
                try {
                    Object[] args = joinPoint.getArgs();
                    if (args != null && args.length > 0) {
                        // 过滤敏感参数
                        Object[] filteredArgs = filterSensitiveParams(args);
                        String paramsJson = objectMapper.writeValueAsString(filteredArgs);
                        // 限制参数长度
                        if (paramsJson.length() > 2000) {
                            paramsJson = paramsJson.substring(0, 2000) + "...";
                        }
                        log.setRequestParams(paramsJson);
                    }
                } catch (Exception e) {
                    log.setRequestParams("参数序列化失败");
                }
            }
        }
        
        // 设置时间
        log.setCreateTime(LocalDateTime.now());
        log.setDeleted(0);
    }
    
    /**
     * 过滤敏感参数
     */
    private Object[] filterSensitiveParams(Object[] args) {
        return Arrays.stream(args)
                .map(arg -> {
                    if (arg == null) return null;
                    
                    String argStr = arg.toString();
                    // 简单的敏感信息过滤
                    if (argStr.toLowerCase().contains("password")) {
                        return "******";
                    }
                    return arg;
                })
                .toArray();
    }
    
    /**
     * 获取HttpServletRequest
     */
    private HttpServletRequest getHttpServletRequest() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            return attributes != null ? attributes.getRequest() : null;
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * 异步记录日志
     */
    private void recordLogAsync(com.example.entity.OperationLog log) {
        // 这里可以使用线程池异步处理，避免影响主业务
        try {
            operationLogService.recordLog(log);
        } catch (Exception e) {
            // 记录日志失败不应该影响业务
            System.err.println("异步记录操作日志失败: " + e.getMessage());
        }
    }
}
